﻿#ifndef __MQTT_H
#define __MQTT_H
#include "mqtt_cfg.h"

#define honts(x)			(((x&0xff)<<8)|((x&0xff00)>>8))
#define	GET_STRING_LEN(X)	(strlen(X)>0?(2+strlen(X)):0)
#define	UINT8TOUINT16(X)	((uint16_t)((X[0]&0xff)<<8|X[1]&0xff))

#define MQTT_POLAY_COPY(ptr,dest,src,len)	do{	\
if (dest != NULL)\
{\
	ptr = (char*)realloc(dest, len + 1);\
	if (ptr != NULL){\
		dest = ptr; \
		memset(ptr, 0, len + 1); \
		memcpy(ptr, src, len); \
	}\
}\
else\
{\
	ptr = (char*)malloc(len + 1);\
	dest = ptr; \
	if (ptr != NULL)\
	{\
		memset(ptr, 0, len + 1);\
		memcpy(ptr, src, len);\
	}\
}\
}while(0)
typedef enum 
{
	RESERVED,		//0		禁止	保留
	CONNECT,		//1		客户端到服务端	客户端请求连接服务端
	CONNACK,		//2		服务端到客户端	连接报文确认
	PUBLISH,		//3		两个方向都允许	发布消息
	PUBACK,			//4		两个方向都允许	QoS 1消息发布收到确认
	PUBREC,			//5		两个方向都允许	发布收到（保证交付第一步）
	PUBREL,			//6		两个方向都允许	发布释放（保证交付第二步）
	PUBCOMP,		//7		两个方向都允许	QoS 2消息发布完成（保证交互第三步）
	SUBSCRIBE,		//8		客户端到服务端	客户端订阅请求
	SUBACK,			//9		服务端到客户端	订阅请求报文确认
	UNSUBSCRIBE,	//10	客户端到服务端	客户端取消订阅请求
	UNSUBACK,		//11	服务端到客户端	取消订阅报文确认
	PINGREQ,		//12	客户端到服务端	心跳请求
	PINGRESP,		//13	服务端到客户端	心跳响应
	DISCONNECT,		//14	客户端到服务端	客户端断开连接
	//RESERVED	,	//15	禁止	保留
}MQTT_type;
typedef enum
{
	CONNECT_FAILED,
	CONNECT_SUCCESS,
}CONNECT_STATE;
typedef union
{
	struct __ConnectFlags {
		uint8_t RESERVED : 1;
		uint8_t CleanSession : 1;
		uint8_t WillFlag : 1;
		uint8_t WillQos : 2;
		uint8_t WillRetain : 1;
		uint8_t PassWordFlag : 1;
		uint8_t UserNameFlag : 1;
	}_ConnectFlags;
	uint8_t Flags;
}ConnectFlags;//连接标志
typedef union
{
	struct __PublishFlags {
		uint8_t RETAIN : 1;
		uint8_t QOS : 2;
		uint8_t DUP : 1;//控制报文的重复分发标志
	}_PublishFlags;
	uint8_t Flags : 4;
}PublishFlags;//发布消息标志
typedef union
{
	struct __Head {

		uint8_t flags : 4;
		uint8_t head_type : 4;
	}_Head;
	uint8_t Flags;
}Head;
typedef struct
{
	char* message;
	int 	len;
	uint8_t Qos;
	uint8_t Dup;
}MQTT_MSG;
typedef struct
{
	Head head;
	uint8_t Remaining_Length[4];//剩余长度字段最大4个字节。
	int Remainlen;
}FixedHeader;//固定报头 Fixed header
typedef enum
{
	MQTT_CLIENT,
	MQTT_SERVER,
}MQTT_Socket_Type;

#define KEEP_ALIVE		30
#define BUFSIZE			1024
#define MAX_LEN			64
typedef struct
{
	char 			PublishTpioc[MAX_LEN];
	uint8_t 		Qos;				//PUBLISH报文的服务质量等级
	uint8_t 		RETAIN;				//PUBLISH报文的保留标志
	uint16_t 		Packet_Identifier;	//报文标识符
	char*			message;
	int 			len;
	uint8_t 		Dup;
}MQTT_PUBLISH;
typedef struct
{
	char 			SubscribeTpioc[MAX_LEN];
	uint8_t  		Subscribe_Result;		//订阅结果0x00 - 最大QoS 0 0x01 - 成功 – 最大QoS 1 0x02 - 成功 – 最大 QoS 2 0x80 - Failure 失败
	uint8_t 		Qos;
	uint16_t 		SUBSCRIBE_Identifier;	//当前接收到的报文标识符
}MQTT_SUBSCRIBE;
typedef struct
{
	char 			UnPublishTpioc[MAX_LEN];//服务端发布消息主题
	uint16_t 		UnPublish_Identifier;	//服务端发布消息报文标识符
	uint8_t 		UnPublishQos;			//服务端发布消息质量
	int				PublishPloay_len;		//消息的長度
	char* 			PublishPloay;
	uint8_t			SubToPublish_flag;		//1-需要转发publish报文
}MQTT_UNPUBLISH;
typedef struct
{
	uint16_t 		Keep_Alive;
	char 			Will_Topic[MAX_LEN];
	char 			Will_Message[MAX_LEN];
	ConnectFlags 	connectflags;
	uint8_t 		currentCleanSession;	//当前会话状态
	uint8_t 		Connack_ErrCode;
	CONNECT_STATE 	connect_state;			//0-断开 1-连接成功
}MQTT_CONNECT;
typedef struct
{
	MQTT_type 		Hope_State;	//希望收到的报文
	uint8_t 		is_recv;	//0-未收到期望的报文 1-收到了
	MQTT_type 		Next_State;	//收到希望的报文后要处理的下一个报文状态
}MQTT_ListHope;
#define NAME_MAX_LEN	10
typedef struct _MQTT MQTT;
struct _MQTT
{
	char			name[NAME_MAX_LEN];
	char 			ClientID[MAX_LEN];
	char 			UserName[MAX_LEN];
	char 			PassWord[MAX_LEN];
	MQTT_CONNECT 	MQTT_Connect;
	MQTT_PUBLISH 	MQTT_Publish;
	MQTT_SUBSCRIBE 	MQTT_Subscribe;
	MQTT_UNPUBLISH 	MQTT_Unpublish;

	MQTT_type 		Current_State;//当前处于什么阶段

	char 			IP[MAX_LEN];
	int 			port;
	int 			(*send_handle)(MQTT* dev);
	int 			(*recv_handle)(MQTT* dev);
	char*			read_buf;					//接收数据缓冲区，默认1024字节
	int 			read_len;					//接收数据缓冲区长度，默认1024字节
	char*			write_buf;					//发送数据缓冲区，默认1024字节
	int 			write_len;					//发送数据缓冲区长度，默认1024字节
	int 			head_index;					//拆包报文，报文接收的索引
	int 			packet_len;					//总长度
	int 			data_err;					//接收数据错误标志
	MQTT_Socket_Type mqtt_socket_type;			//MQTT_CLIENT客户端 MQTT_SERVER服务端
	HANDLE			mqtt_child_thread_handle;	//客户端连接服务端时为每个客户端创建自己的接收信息处理线程
	HANDLE			mqtt_sem;					//收发信号量	
	
	SOCKET			mqtt_socket;				//每个句柄的通信socket
	int				thread_InitFlag;			//每个句柄的线程初始化创建完成标志
};//MQTT参数
#define List_type MQTT
typedef struct _MQTT_LIST MQTT_List;
struct _MQTT_LIST
{
	MQTT_List* prev_node;
	MQTT_List* next_node;
	List_type* node;
};
extern MQTT_List* root; 
void List_Init(void);
int List_Length(MQTT_List* Item);
void List_Insert_forward(MQTT_List* root, MQTT_List* Item);
void List_Insert_back(MQTT_List* root, MQTT_List* Item);
void List_Destroy(MQTT_List* Item);
void List_Delete_node(MQTT_List* Item);
MQTT_List* List_Create_node(List_type* data_node);
void List_print(MQTT_List* Item);
void List_type_print_info(List_type* List_node);
void List_Delete_node_by_data(List_type* List_node);
List_type* List_node_by_SubToPublish(void);
void Check_Subscribe_State(List_type* List_node);
List_type* List_node_by_PublishTpoic(char* publishtpoic);

int Get_Remaining_Length(const char* InBuf, int* remainLen);
char* MQTT_Copy(char* src, char* dest, int len);
int Set_Remaining_Length(char* InBuf, int len);
int Packet_CONNECT(MQTT* dev);
int Unpack_CONNECT(MQTT* dev);
int UnPack_CONNACK(MQTT* dev);
int Packet_CONNACK(MQTT* dev);
int Packet_PUBLISH(MQTT* dev);
int Unpack_PUBLISH(MQTT* dev);
int UnPack_PUBACK(MQTT* dev);
int Packet_PUBACK(MQTT* dev);
int UnPack_PUBREC(MQTT* dev);
int Packet_PUBREC(MQTT* dev);
int UnPack_PUBREL(MQTT* dev);
int Packet_PUBREL(MQTT* dev);
int UnPack_PUBCOMP(MQTT* dev);
int Packet_PUBCOMP(MQTT* dev);
int Packet_SUBSCRIBE(MQTT* dev);
int UnPack_SUBSCRIBE(MQTT* dev);
int UnPack_SUBACK(MQTT* dev);
int Packet_SUBACK(MQTT* dev);
int Packet_UNSUBSCRIBE(MQTT* dev);
int UnPack_UNSUBSCRIBE(MQTT* dev);
int UnPack_UNSUBACK(MQTT* dev);
int Packet_UNSUBACK(MQTT* dev);
int Packet_PINGREQ(MQTT* dev);
int UnPack_PINGREQ(MQTT* dev);
int UnPack_PINGRESP(MQTT* dev);
int Packet_PINGRESP(MQTT* dev);
int Packet_DISCONNECT(MQTT* dev);
int UnPack_DISCONNECT(MQTT* dev);
int MQTT_RecvPoll(MQTT* dev);
MQTT* Create_mqtt(MQTT_Socket_Type TYPE);
void Delete_mqtt(MQTT* dev);
void MQTT_SetClientParameter(MQTT* dev, const char* UserName, const char* PassWord, const char* ClienID, int CleanSession);
int MQTT_Publish(MQTT* dev, const char* PublishTpioc, MQTT_MSG* msg);

#endif


